package com.example.demo.http;

import static java.lang.String.format;

/**
 * User: wcy
 * Date: 2017/11/15
 * Time: 19:14
 */
public final class ChainNode {

    public static final int FLAG_IS_ROOT = 1 << 3;

    public String rootId;
    public String parentId;
    public String nodeId;
    public long flags;
    private String nodeName;
    public int port;
    public static final ChainNode EMPTY = null;

    public String nullableParentId() {
        return root() ? null : parentId;
    }
    public final boolean root() {
        return (flags & FLAG_IS_ROOT) == FLAG_IS_ROOT || (parentId == rootId && parentId == nodeId);
    }

    public ChainNode(String rootId, String parentId, String nodeId, long flags) {
        this.rootId = rootId;
        this.parentId = parentId;
        this.nodeId = nodeId;
        this.flags = flags;
    }

    ChainNode(Builder builder) {
        checkNotNull(builder.nodeId, "nodeId");
        this.rootId = builder.rootId != null ? builder.rootId : builder.nodeId;
        this.parentId = builder.nullableParentId != null ? builder.nullableParentId : this.rootId;
        this.nodeId = builder.nodeId;
        this.flags = builder.flags;
    }


    public static <T> T checkNotNull(T reference, String errorMessageTemplate, Object... errorMessageArgs) {
        if (reference == null) {
            // null异常信息抛出
            throw new NullPointerException(
                    format(errorMessageTemplate, errorMessageArgs));
        }
        return reference;
    }

    public String rootIdString() {
        char[] result = new char[16];
//        writeHexLong(result, 0, rootId);
        return new String(result);
    }

    /** Inspired by {@code okio.Buffer.writeLong} */
    static void writeHexLong(char[] data, int pos, long v) {
        writeHexByte(data, pos + 0,  (byte) ((v >>> 56L) & 0xff));
        writeHexByte(data, pos + 2,  (byte) ((v >>> 48L) & 0xff));
        writeHexByte(data, pos + 4,  (byte) ((v >>> 40L) & 0xff));
        writeHexByte(data, pos + 6,  (byte) ((v >>> 32L) & 0xff));
        writeHexByte(data, pos + 8,  (byte) ((v >>> 24L) & 0xff));
        writeHexByte(data, pos + 10, (byte) ((v >>> 16L) & 0xff));
        writeHexByte(data, pos + 12, (byte) ((v >>> 8L) & 0xff));
        writeHexByte(data, pos + 14, (byte)  (v & 0xff));
    }

    static final char[] HEX_DIGITS =
            {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};

    static void writeHexByte(char[] data, int pos, byte b) {
        data[pos + 0] = HEX_DIGITS[(b >> 4) & 0xf];
        data[pos + 1] = HEX_DIGITS[b & 0xf];
    }

    public static final class Builder {
        String rootId;
        String nullableParentId;
        String nodeId;
        long flags;
        boolean shared;

        Builder(ChainNode source) {
            this.rootId = source.rootId;
            this.nullableParentId = source.nullableParentId();
            this.nodeId = source.nodeId;
            this.flags = source.flags;
        }


        public Builder rootId(String rootId) {
            this.rootId = rootId;
            return this;
        }

        public Builder parentId(String parentId) {
            if (parentId == null) {
                this.flags |= FLAG_IS_ROOT;
            } else {
                this.flags &= ~FLAG_IS_ROOT;
            }
            this.nullableParentId = parentId;
            return this;
        }

        public Builder nodeId(String nodeId) {
            this.nodeId = nodeId;
            return this;
        }

        public Builder flags(long flags) {
            this.flags = flags;
            return this;
        }



        public ChainNode build() {
            return new ChainNode(this);
        }

        Builder() {
        }
    }

    public static Builder builder() {
        return new Builder();
    }
}
